package redis

import (
	"context"
	"github.com/go-redis/redis/v8"
	"sync"
	"time"
	"wskyygyso/api/pkg/logger"
)

// RedisClient redis 服务
type RedisClient struct {
	Client  *redis.Client
	Context context.Context
}

// once 确保全局的 Redis 对象只实例一次
var once sync.Once

// Redis 全局 Redis，使用 db 1
var Redis *RedisClient

// ConnectRedis 连接 redis 数据库，设置全局的 Redis 对象
func Connect(address, username, password string, db int) {
	once.Do(func() {
		Redis = NewClient(address, username, password, db)
	})
}

// NewClient 创建一个新的 redis 连接
func NewClient(address, username, password string, db int) *RedisClient {
	// 初始化自定的 RedisClient 实例
	rds := &RedisClient{}
	// 使用默认的 context
	rds.Context = context.Background()
	// 使用 redis 库里的 NewClient 初始化连接
	rds.Client = redis.NewClient(&redis.Options{
		Addr:     address,
		Username: username,
		Password: password,
		DB:       db,
	})
	// 测试一下连接
	err := rds.Ping()
	logger.LogIf(err)
	return rds
}

// Ping 用以测试 redis 连接是否正常
func (c RedisClient) Ping() error {
	_, err := c.Client.Ping(c.Context).Result()
	return err
}


// Set 存储 key 对应的 value，且设置 expiration 过期时间
func (c RedisClient) Set(key string, value interface{}, expiration time.Duration) bool {
	if err := c.Client.Set(c.Context, key, value, expiration).Err(); err != nil {
		logger.ErrorString("redis", "set", err.Error())
		return false
	}
	return true
}

// Get 获取 key 对应的 value
func (c RedisClient) Get(key string) string {
	res, err := c.Client.Get(c.Context, key).Result()
	if err != nil {
		if err != redis.Nil {
			logger.ErrorString("redis", "get", err.Error())
		}
		return ""
	}
	return res
}

// Has 判断一个 key 是否存在，内部错误和 redis.Nil 都返回 false
func (c RedisClient) Has(key string) bool {
	_, err := c.Client.Get(c.Context, key).Result()
	if err != nil {
		if err != redis.Nil {
			logger.ErrorString("redis", "has", err.Error())
		}
		return false
	}
	return true
}

func (c RedisClient) Del(key ...string) bool {
	if err := c.Client.Del(c.Context, key...).Err(); err != nil {
		logger.ErrorString("redis", "del", err.Error())
		return false
	}
	return true
}

func (c RedisClient) FlushDb() bool {
	if err := c.Client.FlushDB(c.Context).Err(); err != nil {
		logger.ErrorString("redis", "flushDb", err.Error())
		return false
	}
	return true
}

func (c RedisClient) Increment(parameters ...interface{}) bool {
	length := len(parameters)
	switch length {
	case 1:
		//断言是 字符串
		key := parameters[0].(string)
		if err := c.Client.Incr(c.Context, key).Err(); err != nil {
			logger.ErrorString("redis", "incr", err.Error())
			return false
		}
	case 2:
		key := parameters[0].(string)
		val := parameters[1].(int64)
		if err := c.Client.IncrBy(c.Context, key, val).Err(); err != nil {
			logger.ErrorString("redis", "incrBy", err.Error())
			return false
		}

	default:
		logger.ErrorString("redis", "incr", "参数过多")
	}
	return true
}

func (c RedisClient) Decrement(parameters ...interface{}) bool {
	length := len(parameters)
	switch length {
	case 1:
		//断言是 字符串
		key := parameters[0].(string)
		if err := c.Client.Decr(c.Context, key).Err(); err != nil {
			logger.ErrorString("redis", "decr", err.Error())
			return false
		}
	case 2:
		key := parameters[0].(string)
		val := parameters[1].(int64)
		if err := c.Client.DecrBy(c.Context, key, val).Err(); err != nil {
			logger.ErrorString("redis", "decrBy", err.Error())
			return false
		}

	default:
		logger.ErrorString("redis", "decr", "参数过多")
	}
	return true
}
